#include "HalfEdgeMesh.hpp"

namespace zzz {
zzz::HalfEdgeMesh::~HalfEdgeMesh() {
  Clear();
}

void HalfEdgeMesh::Clear() {
  for (zuint i=0; i<half_edges_.size(); i++)
    delete half_edges_[i];
  half_edges_.clear();

  for (zuint i=0; i<boundary_half_edges_.size(); i++)
    delete boundary_half_edges_[i];
  boundary_half_edges_.clear();

  for (zuint i=0; i<vertices_.size(); i++)
    delete vertices_[i];
  vertices_.clear();

  for (zuint i=0; i<faces_.size(); i++)
    delete faces_[i];
  faces_.clear();
}

void HalfEdgeMesh::ConnectEdges(HalfEdge *he1, HalfEdge *he2)
{
  he1->next_=he2;
  he2->prev_=he1;
}

void HalfEdgeMesh::SetTwins(HalfEdge *he1, HalfEdge *he2)
{
  he1->twin_=he2;
  he2->twin_=he1;
}

void HalfEdgeMesh::ConnectFaceEdge(Face *f, HalfEdge *e)
{
  f->half_edge_=e;
  e->left_face_=f;
}

void HalfEdgeMesh::LoadTriMeshGroup(const TriMesh &mesh, zuint group)
{
  for (zuint i=0; i<mesh.pos_.size(); i++) {
    vertices_.push_back(new Vertex(mesh.pos_[i], i));
  }
  vector<HalfEdge*> back_half_edges;
  TriMesh::MeshGroup *g=mesh.groups_[group];
  for (zuint i=0; i<g->facep_.size(); i++) {
    // One face has three half edge and each has a twin edge
    HalfEdge *he[3]={new HalfEdge(false), new HalfEdge(false), new HalfEdge(false)};
    HalfEdge *bhe[3]={new HalfEdge(true), new HalfEdge(true), new HalfEdge(true)};
    Vertex *v[3]={vertices_[g->facep_[i][0]], vertices_[g->facep_[i][1]], vertices_[g->facep_[i][2]]};
    Face *f = new Face(i);

    for (zuint j=0; j<3; j++) {
      // edge and edge
      ConnectEdges(he[j], he[(j+1)%3]);
      ConnectEdges(bhe[j], bhe[(j+1)%3]);
      SetTwins(he[j], bhe[j]);
      // edge and point
      he[j]->start_=v[j];
      v[j]->half_edge_=he[j];
      bhe[j]->start_=v[(j+1)%3];
      v[j]->adj_edges_.push_back(he[j]);
      v[j]->adj_edges_.push_back(bhe[j]);
      // edge and face
      ConnectFaceEdge(f, he[j]);

      half_edges_.push_back(he[i]);
      back_half_edges.push_back(bhe[i]);
    }
    faces_.push_back(f);

    // merge boundary edge
    for (int k=0; k<3; k++) {
      Vertex *start= bhe[k]->start_;
      Vertex *end = bhe[k]->end_vertex();
      for (zuint j=0; j<end->adj_edges_.size(); j++) {
        HalfEdge *curr = end->adj_edges_[j];
        if (curr->boundary_ && curr->end_vertex() == start) {
          ConnectEdges(bhe[k]->prev_, curr->next_);
          ConnectEdges(curr->prev_, bhe[k]->next_);
          SetTwins(bhe[k]->twin_, curr->twin_);
          bhe[k]->start_=NULL;
          curr->start_=NULL;
          break;
        }
      }
    }
  }  // for (zuint i=0; i<g->facep_.size(); i++) {

  for (zuint i=0; i<back_half_edges.size(); i++) {
    if (back_half_edges[i]->start_)
      boundary_half_edges_.push_back(back_half_edges[i]);
    else
      delete back_half_edges[i];
  }
}



};  // namespace zzz